import os;
import sys;
import stdx;
import datetime;
from DBUtils.PooledDB import PooledDB;

try:
	import redis;
except:
	global redis;
	redis = stdx.fromdict({'Redis': object});

__default_dbpool__ = None;
__default_redispool__ = None;

class DBConnect:
	def  __del__(self):
		self.close();
	def __init__(self, dbconn = None, placeholder = None):
		if dbconn:
			self._loglevelist = ['TIP', 'INF', 'IMP', 'ERR'];
			self._placeholder = placeholder;
			self._cursor = dbconn.cursor();
			self._conn = dbconn;
			self._log = None;
	def __enter__(self):
		return self;
	def __exit__(self, exc_type, exc_val, exc_tb):
		return self.close();
	def time(self):
		return stdx.GetDateTimeString();
	def close(self):
		if self._cursor:
			self._cursor.close();
			self._cursor = None;
		if self._conn:
			self._conn.close();
			self._conn = None;
	def commit(self):
		if self._conn: self._conn.commit();
		return self;
	def rollback(self):
		if self._conn: self._conn.rollback();
		return self;
	def getColumns(self):
		return self._cursor.description;
	def setCharset(self, charset):
		if self._conn: self._conn.set_character_set(charset);
		return self;
	def setLogLevel(self, tag):
		vec = ['DBG', 'TIP', 'INF', 'IMP', 'ERR'];
		pos = vec.index(tag);
		if pos >= 0: self._loglevelist = vec[pos:];
	def trace(self, tag, msg, err = None):
		if self._log and tag in self._loglevelist: self._log(tag, msg, err);
	def query(self, sqlcmd, args = ()):
		sql = sqlcmd;
		try:
			if self._placeholder: sql = sql.replace('?', self._placeholder);
			if isinstance(args, str): args = [args];
			elif len(args) == 1: args = [args[0]];
			self._cursor.execute(sql, args);
			res = self._cursor.fetchall();
			if len(args) > 0: self.trace('TIP', 'execute sqlcmd[' + sqlcmd + '] success[' + str(len(res)) + '] with param' + str(list(args)));
			else: self.trace('TIP', 'execute sqlcmd[' + sqlcmd + '] success[' + str(len(res)) + ']');
			return res;
		except BaseException as e:
			if len(args) > 0: self.trace('ERR', 'execute sqlcmd[' + sqlcmd + '] failed[' + str(e) + '] with param' + str(list(args)), e);
			else: self.trace('ERR', 'execute sqlcmd[' + sqlcmd + '] failed[' + str(e) + ']', e);
			raise e;
	def execute(self, sqlcmd, args = ()):
		sql = sqlcmd;
		try:
			if self._placeholder: sql = sql.replace('?', self._placeholder);
			if isinstance(args, str): args = [args];
			elif len(args) == 1: args = [args[0]];
			res = self._cursor.execute(sql, args);
			if len(args) > 0: self.trace('TIP', 'execute sqlcmd[' + sqlcmd + '] success[' + str(res) + '] with param' + str(list(args)));
			else: self.trace('TIP', 'execute sqlcmd[' + sqlcmd + '] success[' + str(res) + ']');
			return res;
		except BaseException as e:
			if len(args) > 0: self.trace('ERR', 'execute sqlcmd[' + sqlcmd + '] failed[' + str(e) + '] with param' + str(list(args)), e);
			else: self.trace('ERR', 'execute sqlcmd[' + sqlcmd + '] failed[' + str(e) + ']', e);
			raise e;
	def queryArray(self, sqlcmd, args = ()):
		rs = self.query(sqlcmd, args);
		cols = self.getColumns();
		data = [];
		for row in rs:
			idx = 0;
			item = {};
			for key in cols:
				if isinstance(row[idx], datetime.datetime): item[key[0].lower()] = row[idx].strftime('%Y-%m-%d %H:%M:%S');
				elif isinstance(row[idx], bytes): item[key[0].lower()] = row[idx].decode();
				elif row[idx] == None: item[key[0].lower()] = '';
				else: item[key[0].lower()] = str(row[idx]);
				idx = idx + 1;
			data.append(item);
		return data;

class DBConnectPool:
	def __init__(self, creator, name, host = None, port = None, user = None, password = None, charset = None):
		if host and port:
			self._name = None;
			self._pool = PooledDB(creator = creator, host = host, port = port, user = user, password = password, db = name, charset = charset, mincached = 1, maxcached = 20);
		else:
			self._name = name;
			self._pool = creator;
			self._charset = charset;
	def get(self):
		if self._name: return DBConnect(self._pool.Connection(self._name));
		else: return DBConnect(self._pool.connection(), '%s');

def GetConnect():
	if __default_dbpool__: return __default_dbpool__.get();
	else: return None;

def SetConnectPool(pool):
	global __default_dbpool__;
	__default_dbpool__ = pool;

class RedisConnect(redis.Redis):
	def close(self):
		return self;
	def __enter__(self):
		return self;
	def __exit__(self, exc_type, exc_val, exc_tb):
		return self.close();

class RedisConnectPool:
	def __init__(self, host, port, password = None):
		self._pool = redis.ConnectionPool(host = host, port = port, password = password);
	def get(self):
		return RedisConnect(connection_pool = self._pool);

def GetRedisConnect():
	if __default_redispool__: return __default_redispool__.get();
	else: return None;

def SetRedisConnectPool(pool):
	global __default_redispool__;
	__default_redispool__ = pool;